package com.xy.smartsms.db.carrierparam;

import android.content.ContentValues;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import com.xy.smartsms.db.carrierparam.entity.OnlineConfigDb;
import com.xy.smartsms.db.carrierparam.entity.OnlineConfigItem;
import com.xy.smartsms.service.carrierparam.UpdateRunnableManager;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import cn.com.xy.sms.sdk.constant.Constant;
import cn.com.xy.sms.sdk.util.StringUtils;

/**
 * Created by admin on 2016/11/23.
 */

public class OnlineConfigManager {
    private static final String TAG = OnlineConfigManager.class.getSimpleName();

    private Context mContext;
    // avoid accessing while remove from map
    private Lock mConfigLock = new ReentrantLock();
    private static OnlineConfigManager sOnlineParamManager = null;
    private Map<String, OnlineConfigItem> mConfigMap = new HashMap<String, OnlineConfigItem>();

    private Map<String, UpdateState> mUpdateStateMap = new HashMap<String, UpdateState>();

    private void insertOrSkip(OnlineConfigItem item) {
        OnlineConfigDb.getInstance().insertOrSkip(item);
    }

    private void putConfigMap(OnlineConfigItem item) {
        mConfigLock.lock();
        mConfigMap.put(item.getKey(), item);
        mConfigLock.unlock();
    }

    public void updateOrInsert(OnlineConfigItem item, ContentValues values) {
        OnlineConfigDb.getInstance().updateOrInsert(item, values);
        putConfigMap(item);
    }

    // _l means lock, namely thread safe
    private OnlineConfigItem getItem_l(String key) {
        OnlineConfigItem item = null;
        mConfigLock.lock();
        item = mConfigMap.get(key);
        mConfigLock.unlock();
        return item;
    }

    private String getConfigValue(String key) {
        OnlineConfigItem item = getItem_l(key);

        if (item == null) {
            Log.v(TAG, "getConfigValue, key =" + key + ", item = item.getValue()");
            item = new OnlineConfigItem(key);
            putConfigMap(item);
        }

        return item.getValue();
    }

    /**
     * 获取周期时间(上一次更新时间+更新周期)
     */
    public long getIntervalTime(String key) {
        if (mConfigMap == null)
            mConfigMap = OnlineConfigDb.getInstance().getAllConfigData();
        int state = mUpdateStateMap.get(key) == null ? OnlineConfigItem.STATUS_SUCCESS : mUpdateStateMap.get(key).getLastUpdateState();

        long lastTime = mUpdateStateMap.get(key) == null ? 0 : mUpdateStateMap.get(key).getLastUpdateTime();
        String newKey = getInterValKey(key, state);
        OnlineConfigItem item = mConfigMap.get(newKey);//获取指定的周期时间
        if (item != null) {
            UpdateRunnableManager.getInstance(mContext).updateMinTime(Long.parseLong(item.getValue()));
            return Long.parseLong(item.getValue()) + lastTime;
        } else{
            return lastTime + OnlineConfigItem.DEFAULT_PERIOD;
        }
    }

    /**
     * 根据状态和key拿对应的周期key
     *
     * @param key
     * @param status
     * @return
     */
    private String getInterValKey(String key, int status) {
        String newKey = null;
        if (OnlineConfigItem.FLAG_WHITE_LIST_LAST_VERSION.equals(key)) {
            newKey = status == OnlineConfigItem.STATUS_SUCCESS ? OnlineConfigItem.KEY_PERIOD_WHITE_SUCCESS : OnlineConfigItem.KEY_PERIOD_WHITE_FAIL;
        } else if (OnlineConfigItem.FLAG_BLACK_LIST_LAST_VERSION.equals(key)) {
            newKey = status == OnlineConfigItem.STATUS_SUCCESS ? OnlineConfigItem.KEY_PERIOD_ESCAPE_SUCCESS : OnlineConfigItem.KEY_PERIOD_ESCAPE_FAIL;
        } else if (OnlineConfigItem.FLAG_CONFIG_LIST_LAST_VERSION.equals(key)) {
            newKey = status == OnlineConfigItem.STATUS_SUCCESS ? OnlineConfigItem.KEY_PERIOD_CONFIG_SUCCESS : OnlineConfigItem.KEY_PERIOD_CONFIG_FAIL;
        }
        return newKey;
    }


    /**
     * 根据功能类型，判断顶层开关
     *
     * @param funcType
     * @return if true, use bizport, otherwise use custom-defined
     */
    public boolean checkTopSwitch(int funcType) {
        if (mConfigMap.isEmpty()) {
            return false;
        }

        String value = getConfigValue(OnlineConfigItem.KEY_SWITCH_BITWISE);
        if (StringUtils.isNull(value) || (Long.valueOf(value) & funcType) == 0) {
            return false;
        } else {
            return true;
        }
    }

    public int getTopSwitch() {
        if (mConfigMap.isEmpty()) {
            return 0;
        }
        String value = getConfigValue(OnlineConfigItem.KEY_SWITCH_BITWISE);
        try {
            if (StringUtils.isNull(value)) {
                return 0;
            } else {
                return Integer.valueOf(value);
            }
        } catch (Throwable t) {
            Log.e(TAG, "checkTopSwitch, t =", t);
        }
        return 0;
    }

    public String getMaxVersion() {
        return OnlineConfigDb.getInstance().getMaxVersion();
    }

    public boolean checkOnResultNull(int funcType) {
        if (mConfigMap.isEmpty()) {
            return false;
        }

        String value = getConfigValue(OnlineConfigItem.KEY_RESULT_NULL_BITWISE);
        if (StringUtils.isNull(value)) {
            return false;
        }

        return (Long.valueOf(value) & funcType) != 0;
    }

    public boolean checkEscapeScene(String scene) {
        if (mConfigMap.isEmpty()) {
            return false;
        }

        String sceneList = getConfigValue(OnlineConfigItem.KEY_BLACK_SCENE_LIST);
        if (StringUtils.isNull(sceneList)) {
            return false;
        }

        if (sceneList.contains(scene + ";")) {
            return true;
        }

        if (sceneList.length() >= 5 && sceneList.contains(scene.substring(0, 5) + ";")) {
            return true;
        }

        if (sceneList.length() >= 2 && sceneList.contains(scene.substring(0, 2) + ";")) {
            return true;
        }

        return false;
    }


    private synchronized void initOnlineConfigMap() {
        if (!mConfigMap.isEmpty()) {
            mConfigMap.clear();
        }
        Log.d(TAG, "initOnlineConfig start");
        initOnlineConfig();
        mConfigMap = OnlineConfigDb.getInstance().getAllConfigData();
    }

    private void initOnlineConfig() {
        insertOrSkip(new OnlineConfigItem(OnlineConfigItem.KEY_PERIOD_CONFIG_SUCCESS)
                .setValue(String.valueOf(1 * Constant.DAY)).setVersion("20170121"));
        insertOrSkip(new OnlineConfigItem(OnlineConfigItem.KEY_PERIOD_CONFIG_FAIL)
                .setValue(String.valueOf(30 * Constant.MINUTE)).setVersion("20170121"));
        insertOrSkip(new OnlineConfigItem(OnlineConfigItem.KEY_PERIOD_ESCAPE_SUCCESS)
                .setValue(String.valueOf(1 * Constant.DAY)).setVersion("20170121"));
        insertOrSkip(new OnlineConfigItem(OnlineConfigItem.KEY_PERIOD_ESCAPE_FAIL)
                .setValue(String.valueOf(30 * Constant.MINUTE)).setVersion("20170121"));
        insertOrSkip(new OnlineConfigItem(OnlineConfigItem.KEY_RESULT_NULL_BITWISE)
                .setValue(String.valueOf(15)).setVersion("20170121"));
        insertOrSkip(new OnlineConfigItem(OnlineConfigItem.KEY_PERIOD_WHITE_SUCCESS)
                .setValue(String.valueOf(1 * Constant.DAY)).setVersion("20170121"));
        insertOrSkip(new OnlineConfigItem(OnlineConfigItem.KEY_PERIOD_WHITE_FAIL)
                .setValue(String.valueOf(30 * Constant.MINUTE)).setVersion("20170121"));
    }

    public void initOnlineConfig(Map<String, String> extend) {
        if (extend != null && extend.containsKey("top_switch_carrier")) {
            String value = extend.get("top_switch_carrier");
            if (TextUtils.isEmpty(value)) {
                value = "146";
            }

            insertOrSkip(new OnlineConfigItem(OnlineConfigItem.KEY_SWITCH_BITWISE)
                    .setValue(value) // 146 / 73
                    .setVersion("20170121"));
        } else {
            insertOrSkip(new OnlineConfigItem(OnlineConfigItem.KEY_SWITCH_BITWISE)
                    .setValue("0")
                    .setVersion("20170121"));
        }

        initOnlineConfigMap();
    }

    public void clearCache() {
        if (mConfigMap != null)
            mConfigMap.clear();
    }

    private OnlineConfigManager(Context context) {
        mContext = context;
        mUpdateStateMap.clear();
        mUpdateStateMap.put(OnlineConfigItem.FLAG_BLACK_LIST_LAST_VERSION, new UpdateState(0, OnlineConfigItem.STATUS_SUCCESS));
        mUpdateStateMap.put(OnlineConfigItem.FLAG_CONFIG_LIST_LAST_VERSION, new UpdateState(0, OnlineConfigItem.STATUS_SUCCESS));
        mUpdateStateMap.put(OnlineConfigItem.FLAG_WHITE_LIST_LAST_VERSION, new UpdateState(0, OnlineConfigItem.STATUS_SUCCESS));
        OnlineConfigDb.getInstance(mContext);
    }


    public static OnlineConfigManager getInstance() {
        return sOnlineParamManager;
    }

    public static OnlineConfigManager getInstance(Context context) {
        synchronized (OnlineConfigManager.class) {
            if (sOnlineParamManager == null) {
                sOnlineParamManager = new OnlineConfigManager(context);
            }
        }
        return sOnlineParamManager;
    }

    public void updateStateMap(String key, long time, int state) {
        mUpdateStateMap.put(key, new UpdateState(time, state));
    }

    private class UpdateState {
        long lastUpdateTime;
        int lastUpdateState;

        public UpdateState(long lastUpdateTime, int lastUpdateState) {
            this.lastUpdateTime = lastUpdateTime;
            this.lastUpdateState = lastUpdateState;
        }

        public long getLastUpdateTime() {
            return lastUpdateTime;
        }

        public int getLastUpdateState() {
            return lastUpdateState;
        }

    }

}
